package impls

import (
	"fmt"
	"reflect"
	"strings"

	"gitee.com/knowgo/gpa/engine/sql/dialects/dialect"
	"gitee.com/knowgo/gpa/engine/sql/metas/schema"
	"gitee.com/knowgo/gpa/engine/sql/types"
)

type baseDialect struct {
	dialect.Dialect
	uri    dialect.URI
	quoter dialect.Quoter
}

func (bd *baseDialect) Init(dialect dialect.Dialect, uri *dialect.URI) error {
	bd.Dialect, bd.uri = dialect, *uri
	return nil
}
func (bd *baseDialect) URI() *dialect.URI {
	return &bd.uri
}

func (bd *baseDialect) QuoteExpr(str string) string {
	return strings.ReplaceAll(str, "\"", "\\\"")
}

// ToSQLType 转为 sql 类型
func (bd *baseDialect) ToSQLType(typ reflect.Type) *types.SQLType {
	return types.Type2SQLType(typ)
}

func (bd *baseDialect) DataTypeOf(val reflect.Value) *types.SQLType {
	return types.Type2SQLType(val.Type())
}

// SQLDropTable 生成删除表的 SQL
func (bd *baseDialect) SQLDropTable(tableName string) (string, error) {
	quote := bd.Quoter().Quote
	// Add 2021.08.02
	tableName = bd.TableNameWithSchema(tableName)
	// tableName = bd.TableNameWithSchema(tableName)
	return fmt.Sprintf("DROP TABLE IF EXISTS %s CASCADE", quote(tableName)), nil
}

func (bd *baseDialect) SQLColumn(col *schema.Column, inlinePrimaryKey bool) (string, error) {
	sql := strings.Builder{}
	// 字段名称
	if err := bd.Quoter().QuoteTo(&sql, col.FieldName()); err != nil {
		return "", err
	}
	if err := sql.WriteByte(' '); err != nil {
		return "", err
	}

	sqlType := bd.SQLType(col)
	// 数据类型
	if _, err := sql.WriteString(sqlType); err != nil {
		return "", err
	}
	if err := sql.WriteByte(' '); err != nil {
		return "", err
	}

	if inlinePrimaryKey && col.IsPrimaryKey {
		// 只有一个字段是主键，且该字段是主键
		if _, err := sql.WriteString("PRIMARY KEY "); err != nil {
			return "", err
		}

		if col.IsAutoIncrement {
			// 该字段是自增类型
			if _, err := sql.WriteString(bd.AutoIncrStr()); err != nil {
				return "", err
			}
			if err := sql.WriteByte(' '); err != nil {
				return "", err
			}
		}
	}
	if col.Default == "" && col.HasDefault {
		typeClass, ok := types.SqlTypes[col.Type.Name]
		if ok {
			if typeClass == types.TEXT_TYPE {
				if _, err := sql.WriteString("DEFAULT ('') "); err != nil {
					return "", err
				}
			}
		}
	} else if col.Default != "" {
		if _, err := sql.WriteString("DEFAULT "); err != nil {
			return "", err
		}
		if _, err := sql.WriteString(col.Default); err != nil {
			return "", err
		}
		if err := sql.WriteByte(' '); err != nil {
			return "", err
		}
	}

	if col.Nullable {
		if _, err := sql.WriteString("NULL "); err != nil {
			return "", err
		}
	} else {
		if _, err := sql.WriteString("NOT NULL "); err != nil {
			return "", err
		}
	}

	return sql.String(), nil
}

func (bd *baseDialect) SQLAddColumn(tableName string, col *schema.Column) string {
	s, _ := bd.SQLColumn(col, true)
	// Add 2021.08.02
	tableName = bd.TableNameWithSchema(tableName)
	return fmt.Sprintf("ALTER TABLE %v ADD %v", bd.Quoter().Quote(tableName), s)
}

func (bd *baseDialect) SQLModifyColumn(tableName string, col *schema.Column) string {
	s, _ := bd.SQLColumn(col, false)
	// Add 2021.08.02
	tableName = bd.TableNameWithSchema(tableName)
	return fmt.Sprintf("ALTER TABLE %s MODIFY COLUMN %s", bd.Quoter().Quote(tableName), s)
}

func (bd *baseDialect) SQLCreateIndex(tableName string, index *schema.Index) string {
	quoter := bd.Dialect.Quoter()
	var unique string
	var idxName string
	if index.Type == types.UniqueType {
		unique = " UNIQUE"
	}
	idxName = index.XName(tableName)
	return fmt.Sprintf("CREATE%s INDEX %v ON %v (%v)", unique,
		quoter.Quote(idxName), quoter.Quote(tableName),
		quoter.Join(index.Cols, ","))
}

func (bd *baseDialect) SQLDropIndex(tableName string, index *schema.Index) string {
	quote := bd.Dialect.Quoter().Quote
	var name string
	if index.Regular {
		name = index.XName(tableName)
	} else {
		name = index.Name
	}
	return fmt.Sprintf("DROP INDEX %v ON %s", quote(name), quote(tableName))
}

// func (bd *baseDialect) CreateInsertSQL(sql *intf.SQL) (string, []*intf.SQLParam) {
// 	return fmt.Sprintf("INSERT INTO %s (%s) VALUES (%s)",
// 		sql.TableName,
// 		strings.Join(sql.Columns, ","),
// 		strings.Join(sql.ParamPlaceHolder, ",")), sql.Params
// }
// func (bd *baseDialect) CreateUpdateSQL(sql *intf.SQL) (string, []*intf.SQLParam, []*intf.SQLParam) {
// 	// quoter := bd.Dialect.Quoter()
// 	if sql.Where != "" {
// 		sqlStr := fmt.Sprintf("UPDATE %s SET %s WHERE %s",
// 			sql.TableName,
// 			strings.Join(sql.Columns, ","),
// 			sql.Where)
// 		return bd.QuoteExpr(sqlStr), sql.Params, sql.WhereParams
// 	}
// 	sqlStr := fmt.Sprintf("UPDATE %s SET %s",
// 		sql.TableName,
// 		strings.Join(sql.Columns, ","))
// 	return bd.QuoteExpr(sqlStr), sql.Params, nil
// }
// func (bd *baseDialect) CreateDeleteSQL(sql *intf.SQL) (string, []*intf.SQLParam) {
// 	// quoter := bd.Dialect.Quoter()
// 	if sql.Where != "" {
// 		sqlStr := fmt.Sprintf("DELETE FROM %s WHERE %s",
// 			sql.TableName,
// 			sql.Where)
// 		return bd.QuoteExpr(sqlStr), sql.WhereParams
// 	}
// 	sqlStr := fmt.Sprintf("DELETE FROM %s",
// 		sql.TableName)
// 	return bd.QuoteExpr(sqlStr), sql.Params
// }

// func (bd *baseDialect) CreateQuerySQL(sql *intf.SQL) (string, []*intf.SQLParam) {
// 	if sql.Where != "" {
// 		sqlStr := fmt.Sprintf("SELECT %s FROM %s WHERE %s",
// 			strings.Join(sql.Columns, ","),
// 			sql.TableName,
// 			sql.Where)
// 		return bd.QuoteExpr(sqlStr), sql.WhereParams
// 	}
// 	sqlStr := fmt.Sprintf("SELECT %s FROM %s",
// 		strings.Join(sql.Columns, ","),
// 		sql.TableName)
// 	return bd.QuoteExpr(sqlStr), sql.WhereParams
// }
